#include "VideoRead.h"

void testJumpRead()
{
	//VideoCapture cap("../../_FGS/vid/GOPR2382_cab.avi");

	vector<int> frm_id;
	frm_id.resize(0); frm_id.reserve(200);
	for(int f = 550;f<5300;f+=50) frm_id.push_back( f );

	LcVideoReadVec my_reader;

	my_reader.root = "../../_FGS/";
	
	my_reader.set( frm_id );

	for(int i = 0 ; i < 10;i++)
	{
		Mat frm,gt;
		my_reader.readNext( frm );
		my_reader.getLabel( gt );

		Mat dsp;
		cvtColor(gt,dsp,CV_GRAY2BGR);

		addWeighted(frm,0.5,dsp,0.5,0, dsp);
		imshow("debug",dsp);cv::waitKey(100);
	}

	cv::waitKey(0);

}

bool LcVideoReadExt::IF_GRAY = true;

LcVideoRead::LcVideoRead()
{
	root = "C:/Users/LC1332/Desktop/SnapCut/_FGS/";
	video_name = "GOPR2382_cab";
	ext = ".avi";
	f_start = 150;
	f_end = 350;
	f_rate = 50;
	t_win = 2;
	f = 0;
	scale = 0.5;
	veb = 1;
}

int LcVideoRead::getN()
{
	if((f_end-f_start)%f_rate!=0)
		return (f_end-f_start)/f_rate;
	else
		return (f_end-f_start)/f_rate+1;
}

void testLcVideoRead()
{
	LcVideoReadExt test;

	test.t_win = 1;
	//test.open();

	for(int k = 0;k<2;k++)
	{
		for(int i = 0;i<120;i++)
		{
			Mat frm;
			int j = test.read(frm);
			cout << i << " " << j << " ";
			cout << test.f - test.t_win<< endl;
			if(j>=0)
			{
				imshow("show",frm);
				cv::waitKey(2);
			}
		}
		test.reset();
	}

	for(int k = 0;k<2;k++)
	{
		for(int i = 0;i<5;i++)
		{
			Mat frm;
			int j = test.readNext(frm);
			if(j>=0)
			{
				imshow("show",frm);
				cv::waitKey(200);
			}
		}
		test.reset();
	}

	system("pause");
}


void testLabelRead()
{
	LcVideoReadExt test;

	test.t_win = 1;

	for(int k = 0;k<2;k++)
	{
		for(int i = 0;i<5;i++)
		{
			Mat frm;
			int j = test.readNext(frm);

			Mat lab;
			test.getLabel(lab);

			

			if(j>=0)
			{
				imshow("show",frm);

				if(lab.data) imshow("show lab", lab);

				cv::waitKey(200);
			}
		}
		test.reset();
	}
	cv::waitKey(0);
}

void LcVideoRead::getLabel(Mat & lab)
{
	int id = getf();

	string msktyp = "msk_fg/";

	stringstream ss;
	ss << root + msktyp + video_name + "/" + video_name + "_maskgt_" << id <<".jpg";

	if(veb) cout << "load " << ss.str() << endl;

	lab = imread(ss.str(),0);
}


int LcVideoRead::getf()
{
	return f-t_win;
}

void LcVideoRead::reset()
{
	if(cap.isOpened())
		cap.release();
	f = 0;
}



void LcVideoRead::open()
{
	string vidfile = root + "vid/" + video_name + ext;

	cout << "Opening video: " << vidfile << endl;

	cap = VideoCapture(vidfile);

	if(!cap.isOpened())
	{
		cout << "failed to open" << endl;
		system("pause");
		exit(1);
	}

	cout << "opened" << endl;

	Mat temp;

	f = -1;
	//sorry it's a patch since I set a wrong start num of f
	// if remove this sentence, image will not match with the label

	while(f< f_start-t_win-1)
	{
		cap >> temp; f++;
	}

	temp.release();

}

int LcVideoRead::read_one_frame(Mat & frm)
{
	Mat temp;
	cap >> temp; f++;
	if(! temp.data) return 0;
	Mat temp2;
	resize(temp,temp2,Size(),scale,scale);
	temp2.copyTo(frm);	
	return 1;
}

int LcVideoRead::read(Mat & frm)
{
	if(f == 0)
	{
		open();
	}

	if(f>f_end+t_win+1) return -1;


	if(!read_one_frame(frm)) return -1;

	if(f>f_end) return -1;

	if(f<t_win) return 1;
	if(((f-f_start)%f_rate)!=0) return 1;
	if(f<f_start) return 1;
	
	return 0;
}

int LcVideoRead::readNext(Mat & frm)
{
	int v = read(frm);
	if(v==1) return readNext(frm);
	return v;
}

//=============================


void LcVideoReadExt::reset()
{
	if(cap.isOpened())
		cap.release();
	f = 0;
}


int LcVideoReadExt::read(Mat & frm)
{
	return read(frm,NULL);
}


int LcVideoReadExt::read(Mat & frm, vector<Mat> * frm_array)
{
	

	if(f == 0)
	{
		open();
		array_init();
	}

	if(f>f_end+t_win+1) return -1;

	Mat temp;

	if(!read_one_frame( temp) ) return -1;
	loop_id = loop_add( loop_id );

	int f_now = f - t_win;

	img_array[loop_id] = temp;

	img_array[ loop_minus(loop_id, t_win) ].copyTo(frm);

	if(frm_array!=NULL)
	{
		getfrms(frm_array);
	}
	
	if(f_now>f_end) return -1;

	if(f_now<t_win) return 1;
	if(((f_now-f_start)%f_rate)!=0) return 1;
	if(f_now<f_start) return 1;
	
	return 0;
}

void LcVideoReadExt::getfrms( vector<Mat> * frm_array)
{
	int id = loop_minus(loop_id, 2*t_win);

	vector< Mat > & imgs = *frm_array;

	imgs.resize( 2* t_win + 1);

	for(int i = 0;i< 1+ 2* t_win;i++)
	{
		//imgs[i] = img_array[ id ];
		img_array[ id ].copyTo(imgs[i]);
		id = loop_add( id, 1);
	}

}


int LcVideoReadExt::readNext(Mat & frm)
{
	t_win = 0;
	if(f==0) open();
	f++;
	while( (getf()  - f_start)%f_rate !=0 ) f++;

	if(getf()>f_end) return -1;

	cap.set( CV_CAP_PROP_POS_FRAMES, double(getf()));
	f--;
	if(!read_one_frame( frm )) return -1;
	else{ return 0;}
}

int LcVideoReadExt::readNext(Mat & frm, vector<Mat>  * frm_array)
{
	
	int v = read(frm,NULL);

	while(v==1) v = read(frm,NULL);

	if(frm_array !=NULL)
	{
		getfrms(frm_array);
	}
	
	return v;
}



int LcVideoReadExt::loop_add(int loop_id,int i)
{
	loop_id+=i;
	while(loop_id>=t_win*2+1) loop_id-=(t_win*2+1);
	return loop_id;
}

int LcVideoReadExt::loop_minus(int loop_id, int i)
{
	loop_id-=i;
	while(loop_id<0) loop_id+=(t_win*2+1);
	return loop_id;
}

void LcVideoReadExt::array_init()
{
	img_array.resize(t_win*2+1);

	loop_id = 0;//id of mid frame

	Mat first_image;

	read_one_frame( first_image );

	for(int i = 0;i<t_win*2+1;i++) img_array[i] = first_image;
	//to avoid broken build it at first

	while(f < f_start+t_win-1)
	{
		Mat temp;

		if(!read_one_frame( temp) ){
			cout << " The video is not enough long " << endl;
			system("pause");
			exit(1);
		}

		loop_id = loop_add( loop_id );

		img_array[loop_id] = temp;
	}
}
//===================================

//class LcVideoReadVec
//{
//public:
//	void open();
//	int read(Mat & frm);
//	int readNext(Mat & frm);
//	void reset();
//  LcVideoReadVec();
//
//	void set(vector<int> & n_frm_id);
//	vector<int> frm_id;
//private:
//	int p;
//};

int LcVideoReadVec::getN()
{
	return (int) frm_id.size();
}

LcVideoReadVec::LcVideoReadVec()
{
	p = -1;
}

LcVideoReadVec::LcVideoReadVec( LcVideoRead & reader )
{
	root = reader.root;
	video_name = reader.video_name;
	ext = reader.ext;
	p = -1;
}

int LcVideoReadVec::getf()
{
	return f;
}

void LcVideoReadVec::open()
{
	string vidfile = root + "vid/" + video_name + ext;

	cout << "Opening video: " << vidfile << endl;

	cap = VideoCapture(vidfile);

	if(!cap.isOpened())
	{
		cout << "failed to open" << endl;
		system("pause");
		exit(1);
	}

	cout << "opened" << endl;

	p = -1;
}


void LcVideoReadVec::reset()
{
	if(frm_id.size()>0) f = frm_id[0]-1;
	p = -1;
}

void LcVideoReadVec::set(vector<int> & n_frm_id)
{
	frm_id = n_frm_id;
	p = -1;
}

int LcVideoReadVec::readNext(Mat & frm)
{
	if(p==-1) open();

	if(p<(int)frm_id.size()-1)
	{
		p++;
		f = frm_id[p];
		cap.set( CV_CAP_PROP_POS_FRAMES, double(f));
		read_frame(frm);
		return 0;
	}
	else return -1;
}

void LcVideoReadVec::read_frame( Mat & frm)
{
	Mat temp;
	cap>>temp;
	if(!temp.data) return;
	cv::resize( temp, frm , Size() , scale , scale);
}

int LcVideoReadVec::read( Mat & frm )
{
	if(p>=(int)frm_id.size()-1)return -1;

	if(p==-1)
	{
		open();
	}


	read_frame( frm);
	f++;
	if(!frm.data) return -1;

	if(p==int(frm_id.size()-1) || frm_id[p+1]!=f) return 1;

	p++;
	return 0;
}